﻿using NPOI.SS.Formula.Functions;

using PLCS.App.Shared.Events;
using PLCS.App.Shared.Models;
using PLCS.Shared.Common.Constant;
using PLCS.Shared.Common.Extensions;
using PLCS.Shared.Common.Helper;

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace PLCS.App.Shared.Views.UserControls.Chlidren
{
    /// <summary>
    /// FramePreviewView.xaml 的交互逻辑
    /// </summary>
    public partial class FramePreviewView : UserControl
    {
        private double ratio;//系数、比例
        private IEventAggregator _eventAggregator;

        /// <summary>
        /// 固定的边
        /// </summary>
        public FixedSideEnum FixedSide
        {
            get { return (FixedSideEnum)GetValue(FixedSideProperty); }
            set { SetValue(FixedSideProperty, value); }
        }

        // Using a DependencyProperty as the backing store for FixedSide.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FixedSideProperty =
            DependencyProperty.Register("FixedSide", typeof(FixedSideEnum), typeof(FramePreviewView), new PropertyMetadata(FixedSideEnum.Height));

        public MapMode MapMode
        {
            get { return (MapMode)GetValue(MapModeProperty); }
            set { SetValue(MapModeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MapMode.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MapModeProperty =
            DependencyProperty.Register("MapMode", typeof(MapMode), typeof(FramePreviewView), new PropertyMetadata(MapMode.Default));

        public double CadW
        {
            get { return (double)GetValue(CadWProperty); }
            set { SetValue(CadWProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CadW.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CadWProperty =
            DependencyProperty.Register("CadW", typeof(double), typeof(FramePreviewView), new PropertyMetadata(0.0));

        public double CadH
        {
            get { return (double)GetValue(CadHProperty); }
            set { SetValue(CadHProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CadH.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CadHProperty =
            DependencyProperty.Register("CadH", typeof(double), typeof(FramePreviewView), new PropertyMetadata(0.0));

        public ObservableCollection<ModelControl> ModelControls
        {
            get { return (ObservableCollection<ModelControl>)GetValue(ModelControlsProperty); }
            set { SetValue(ModelControlsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ModelControls.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ModelControlsProperty =
            DependencyProperty.Register("ModelControls", typeof(ObservableCollection<ModelControl>), typeof(FramePreviewView), new PropertyMetadata(new ObservableCollection<ModelControl>()));

        /// <summary>
        /// 元素点击事件
        /// </summary>
        public ICommand FrameCommand
        {
            get { return (ICommand)GetValue(FrameCommandProperty); }
            set { SetValue(FrameCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemCommand.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FrameCommandProperty =
            DependencyProperty.Register("FrameCommand", typeof(ICommand), typeof(FramePreviewView));

        public ICommand DeleteCommand
        {
            get { return (ICommand)GetValue(DeleteCommandProperty); }
            set { SetValue(DeleteCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DeleteCommand.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DeleteCommandProperty =
            DependencyProperty.Register("DeleteCommand", typeof(ICommand), typeof(FramePreviewView));

        public ICommand CopyCommand
        {
            get { return (ICommand)GetValue(CopyCommandProperty); }
            set { SetValue(CopyCommandProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CopyCommand.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CopyCommandProperty =
            DependencyProperty.Register("CopyCommand", typeof(ICommand), typeof(FramePreviewView));

        public FramePreviewView()
        {
            InitializeComponent();
            SizeChanged += (o, e) => InitFrame();
            _eventAggregator = ContainerLocator.Container.Resolve<IEventAggregator>();
            _eventAggregator.GetEvent<ReloadEvent>().Subscribe(InitFrame);
        }

        public async void InitFrame()
        {
            double cadw = CadW;
            double cadh = CadH;
            frame.Children.Clear();

            switch (FixedSide)
            {
                case FixedSideEnum.Height:
                    frame.Height = RenderSize.Height;
                    switch (MapMode)
                    {
                        case MapMode.Default:
                            frame.Width = (cadw * frame.Height) / cadh;
                            ratio = frame.Height / cadh;
                            break;

                        case MapMode.Overturn:
                            frame.Width = (cadh * frame.Height) / cadw;
                            ratio = frame.Height / cadw;
                            break;

                        default:
                            break;
                    }
                    break;

                case FixedSideEnum.Width:
                    frame.Width = RenderSize.Width;
                    switch (MapMode)
                    {
                        case MapMode.Default:

                            frame.Height = (cadh * frame.Width) / cadw;
                            ratio = frame.Height / cadh;
                            break;

                        case MapMode.Overturn:
                            frame.Height = (cadw * frame.Width) / cadh;
                            ratio = frame.Height / cadw;
                            break;

                        default:
                            break;
                    }

                    break;

                default:
                    break;
            }

            #region 添加元素

            //var table = TableHelper.ExcelToTable(fileName);
            IEnumerable<ModelControl> modelConfigs = ModelControls;
            foreach (var row in modelConfigs)
            {
                await Dispatcher.BeginInvoke(() =>
                {
                    var control = new UIElement();
                    string controltype = row.ControlStyle;
                    var cm = new ContextMenu { Name = "cm", StaysOpen = true };
                    var copyMenuItem = new MenuItem { Header = "Copy", Command = CopyCommand, CommandParameter = row };
                    var deleteMenuItem = new MenuItem { Header = "Delete", Command = DeleteCommand, CommandParameter = row };
                    cm.Items.Add(copyMenuItem);
                    cm.Items.Add(deleteMenuItem);
                    //control
                    switch (controltype)
                    {
                        case "VirtualStation":
                            break;
                        //货位
                        case "RowGoods":
                            RowGoods rowGoods = new RowGoods()
                            {
                                SName = $"{row.SName ?? "W101"}",
                                Width = Convert.ToDouble(row.Width) * ratio,
                                Height = Convert.ToDouble(row.Height) * ratio,
                                ColumnCount = Convert.ToInt32(row.ColumnCount),
                                NoDisplayColumn = row.NoDisplayColumn,
                                Roadway = Convert.ToInt32(row.Roadway),
                                LayerCount = Convert.ToInt32(row.LayerCount),
                                Platepos = row.Platepos,
                                Command = FrameCommand,
                                CommandParameter = row,
                                ContextMenu = cm
                            };

                            switch (MapMode)
                            {
                                case MapMode.Default:
                                    Canvas.SetLeft(rowGoods, Convert.ToDouble(row.X) * ratio);
                                    Canvas.SetTop(rowGoods, Convert.ToDouble(row.Y) * ratio);
                                    break;

                                case MapMode.Overturn:
                                    Canvas.SetLeft(rowGoods, Convert.ToDouble(row.Y) * ratio);
                                    Canvas.SetTop(rowGoods, Convert.ToDouble(row.X) * ratio);
                                    break;

                                default:
                                    break;
                            }
                            frame.Children.Add(rowGoods);
                            RegisterName(frame, $"{rowGoods.SName}", rowGoods);
                            break;
                        //工位
                        case "Station":
                            Station station = new()
                            {
                                BorderThickness = new Thickness(0),
                                Background = Brushes.DimGray,
                                SName = $"{row.SName ?? "W101"}",
                                Name = $"{row.SName ?? "W101"}",
                                Width = Convert.ToDouble(row.Width) * ratio,
                                Height = Convert.ToDouble(row.Height) * ratio,
                                Command = FrameCommand,
                                CommandParameter = row,
                                ContextMenu = cm
                            };
                            switch (MapMode)
                            {
                                case MapMode.Default:
                                    Canvas.SetLeft(station, Convert.ToDouble(row.X) * ratio);
                                    Canvas.SetTop(station, Convert.ToDouble(row.Y) * ratio);
                                    break;

                                case MapMode.Overturn:
                                    Canvas.SetLeft(station, Convert.ToDouble(row.Y) * ratio);
                                    Canvas.SetTop(station, Convert.ToDouble(row.X) * ratio);
                                    break;

                                default:
                                    break;
                            }
                            frame.Children.Add(station);
                            RegisterName(frame, station.SName, station);
                            //frame.RegisterName($"{station.SName}", station);
                            break;
                        //输送线
                        case "ConveyorLine":
                            ConveyorLine conveyorLine = new()
                            {
                                SName = $"{row.SName ?? "W101"}",
                                Name = $"{row.SName ?? "W101"}",
                                Width = Convert.ToDouble(row.Width) * ratio,
                                Height = Convert.ToDouble(row.Height) * ratio,
                                Command = FrameCommand,
                                CommandParameter = row,
                                ContextMenu = cm
                            };
                            switch (MapMode)
                            {
                                case MapMode.Default:
                                    Canvas.SetLeft(conveyorLine, Convert.ToDouble(row.X) * ratio);
                                    Canvas.SetTop(conveyorLine, Convert.ToDouble(row.Y) * ratio);
                                    break;

                                case MapMode.Overturn:
                                    Canvas.SetLeft(conveyorLine, Convert.ToDouble(row.Y) * ratio);
                                    Canvas.SetTop(conveyorLine, Convert.ToDouble(row.X) * ratio);
                                    break;

                                default:
                                    break;
                            }
                            frame.Children.Add(conveyorLine);
                            RegisterName(frame, conveyorLine.SName, conveyorLine);
                            break;

                        //输送线
                        case "Pipeline":
                            Pipeline pipeline = new()
                            {
                                StationCount = int.Parse(row.Capacity ?? "6"),
                                SName = $"{row.SName ?? "WP101"}",
                                Name = $"{row.SName ?? "WP101"}",
                                Width = Convert.ToDouble(row.Width) * ratio,
                                Height = Convert.ToDouble(row.Height) * ratio,
                                Command = FrameCommand,
                                CommandParameter = row,
                                ContextMenu = cm
                            };
                            switch (MapMode)
                            {
                                case MapMode.Default:
                                    Canvas.SetLeft(pipeline, Convert.ToDouble(row.X) * ratio);
                                    Canvas.SetTop(pipeline, Convert.ToDouble(row.Y) * ratio);
                                    break;

                                case MapMode.Overturn:
                                    Canvas.SetLeft(pipeline, Convert.ToDouble(row.Y) * ratio);
                                    Canvas.SetTop(pipeline, Convert.ToDouble(row.X) * ratio);
                                    break;

                                default:
                                    break;
                            }
                            frame.Children.Add(pipeline);
                            RegisterName(frame, pipeline.SName, pipeline);
                            break;

                        case "AgvStation":
                            AgvStation agvStation = new AgvStation()
                            {
                                SName = $"{row.SName ?? "WP101"}",
                                Name = $"{row.SName ?? "WP101"}",
                                Width = Convert.ToDouble(row.Width) * ratio,
                                Height = Convert.ToDouble(row.Height) * ratio,
                                Command = FrameCommand,
                                CommandParameter = row,
                                ContextMenu = cm
                            };
                            switch (MapMode)
                            {
                                case MapMode.Default:
                                    Canvas.SetLeft(agvStation, Convert.ToDouble(row.X) * ratio);
                                    Canvas.SetTop(agvStation, Convert.ToDouble(row.Y) * ratio);
                                    break;

                                case MapMode.Overturn:
                                    Canvas.SetLeft(agvStation, Convert.ToDouble(row.Y) * ratio);
                                    Canvas.SetTop(agvStation, Convert.ToDouble(row.X) * ratio);
                                    break;

                                default:
                                    break;
                            }
                            frame.Children.Add(agvStation);
                            RegisterName(frame, agvStation.SName, agvStation);
                            //frame.RegisterName($"{agvStation.SName}", agvStation);

                            break;
                        //轨道
                        case "Track":
                            Track track = new Chlidren.Track()
                            {
                                SName = $"{row.SName ?? "WP101"}",
                                Name = $"{row.SName ?? "WP101"}",
                                Width = Convert.ToDouble(row.Width) * ratio,
                                Height = Convert.ToDouble(row.Height) * ratio,
                                PlatePos = row.Platepos,
                                Command = FrameCommand,
                                CommandParameter = row,
                                ContextMenu = cm
                            };
                            Canvas.SetZIndex(track, -1);
                            // track.PlatePos = row["Platepos"]?.ToString() ?? track.PlatePos;
                            switch (MapMode)
                            {
                                case MapMode.Default:
                                    Canvas.SetLeft(track, Convert.ToDouble(row.X) * ratio);
                                    Canvas.SetTop(track, Convert.ToDouble(row.Y) * ratio);
                                    break;

                                case MapMode.Overturn:
                                    Canvas.SetLeft(track, Convert.ToDouble(row.Y) * ratio);
                                    Canvas.SetTop(track, Convert.ToDouble(row.X) * ratio);
                                    break;

                                default:
                                    break;
                            }
                            frame.Children.Add(track);
                            RegisterName(frame, track.SName, track);
                            //track.RegisterName($"{track.SName}", track);

                            break;

                        case "RotaryTable":
                            RotaryTable rotaryTable = new RotaryTable()
                            {
                                SName = $"{row.SName ?? "WP101"}",
                                Name = $"{row.SName ?? "WP101"}",
                                Width = Convert.ToDouble(row.Width) * ratio,
                                Height = Convert.ToDouble(row.Height) * ratio,
                                Command = FrameCommand,
                                CommandParameter = row,
                                ContextMenu = cm
                            };
                            switch (MapMode)
                            {
                                case MapMode.Default:
                                    Canvas.SetLeft(rotaryTable, Convert.ToDouble(row.X) * ratio);
                                    Canvas.SetTop(rotaryTable, Convert.ToDouble(row.Y) * ratio);
                                    break;

                                case MapMode.Overturn:
                                    Canvas.SetLeft(rotaryTable, Convert.ToDouble(row.Y) * ratio);
                                    Canvas.SetTop(rotaryTable, Convert.ToDouble(row.X) * ratio);
                                    break;

                                default:
                                    break;
                            }
                            frame.Children.Add(rotaryTable);
                            RegisterName(frame, rotaryTable.SName, rotaryTable);
                            //frame.RegisterName($"{rotaryTable.SName}", rotaryTable);
                            rotaryTable.RotateAnimation(0, 90);
                            break;
                        //RGV
                        case "RGV":
                            RGV rgv = new RGV()
                            {
                                SName = $"{row.SName ?? "WP101"}",
                                Name = $"{row.SName ?? "WP101"}",
                                Width = Convert.ToDouble(row.Width) * ratio,
                                Height = Convert.ToDouble(row.Height) * ratio,
                                Command = FrameCommand,
                                CommandParameter = row,
                                ContextMenu = cm
                            };
                            switch (MapMode)
                            {
                                case MapMode.Default:
                                    Canvas.SetLeft(rgv, Convert.ToDouble(row.X) * ratio);
                                    Canvas.SetTop(rgv, Convert.ToDouble(row.Y) * ratio);
                                    break;

                                case MapMode.Overturn:
                                    Canvas.SetLeft(rgv, Convert.ToDouble(row.Y) * ratio);
                                    Canvas.SetTop(rgv, Convert.ToDouble(row.X) * ratio);
                                    break;

                                default:
                                    break;
                            }
                            frame.Children.Add(rgv);
                            RegisterName(frame, rgv.SName, rgv);
                            //frame.RegisterName($"{rgv.SName}", rgv);

                            break;

                        case "Stacker":
                            Stacker stacker = new Stacker()
                            {
                                SName = $"{row.SName ?? "WP101"}",
                                Name = $"{row.SName ?? "WP101"}",
                                Width = Convert.ToDouble(row.Width) * ratio,
                                Height = Convert.ToDouble(row.Height) * ratio,
                                Command = FrameCommand,
                                CommandParameter = row,
                                ContextMenu = cm
                            };
                            switch (MapMode)
                            {
                                case MapMode.Default:
                                    Canvas.SetLeft(stacker, Convert.ToDouble(row.X) * ratio);
                                    Canvas.SetTop(stacker, Convert.ToDouble(row.Y) * ratio);
                                    break;

                                case MapMode.Overturn:
                                    Canvas.SetLeft(stacker, Convert.ToDouble(row.Y) * ratio);
                                    Canvas.SetTop(stacker, Convert.ToDouble(row.X) * ratio);
                                    break;

                                default:
                                    break;
                            }
                            frame.Children.Add(stacker);
                            RegisterName(frame, stacker.SName, stacker);
                            //frame.RegisterName($"{rgv.SName}", rgv);

                            break;

                        default:
                            break;
                    }
                }, DispatcherPriority.Send);
            }

            #endregion 添加元素
        }

        public static void RegisterName<T>(Canvas frame, string name, T obj) where T : FrameworkElement
        {
            // 判断指定名字是否已经被注册
            if (frame != null && frame.FindName(name) != null)
            {
                // 名字已经被注册,则注销
                frame.UnregisterName(name);
            }

            // 注册新对象
            frame.RegisterName(name, obj);
        }
    }
}